import '@/assets/mapbox/libs/draw/mapbox-gl-draw.css'
import MapBoxDraw from '@/assets/mapbox/libs/draw/mapbox-gl-draw.js'

import * as turf from '@turf/turf';
import PlotBaseClass from '@/assets/js/plot/AreaPlotBase.js'

/**
         * Package: StraightArrow
         * 直箭头：1.控制点组；2.构成的所有点部分
         * 方法：用于通过控制点计算箭头的所有绘制点
         */
const doubleClickZoom = {
  enable: ctx => {
    setTimeout(() => {
      // First check we've got a map and some context.
      if (
        !ctx.map ||
        !ctx.map.doubleClickZoom ||
        !ctx._ctx ||
        !ctx._ctx.store ||
        !ctx._ctx.store.getInitialConfigValue
      )
        return;
      // Now check initial state wasn't false (we leave it disabled if so)
      if (!ctx._ctx.store.getInitialConfigValue("doubleClickZoom")) return;
      ctx.map.doubleClickZoom.enable();

      //state.controlPoints =[];
    }, 0);
  },
  disable(ctx) {
    setTimeout(() => {
      if (!ctx.map || !ctx.map.doubleClickZoom) return;
      // Always disable here, as it's necessary in some cases.
      ctx.map.doubleClickZoom.disable();
    }, 0);
  }
};

const DrawStraightArrow = {
  // When the mode starts this function will be called.
  onSetup: function(opts) {
    const straightArrow = this.newFeature({
      type: "Feature",
      properties: {},
      geometry: {
        type: "Polygon",
        coordinates: [[]]
      }
    });
    this.controlPoints = [];

    this.addFeature(straightArrow);
    this.clearSelectedFeatures();
    doubleClickZoom.disable(this);
    this.updateUIClasses({ mouse: "add" });
    this.setActionableState({
      trash: true
    });
    return {
      straightArrow
    };
  },
 // controlPoints:[],
  //双击结束
  clickOnVertex:function(state, e) {
    if (
      state.controlPoints &&
      state.controlPoints[state.controlPoints.length-1].x !== e.lngLat.lng &&
      state.controlPoints[state.controlPoints.length-1].y !== e.lngLat.lat
    ) {
      this.updateUIClasses({ mouse: "pointer" }); 
      this.changeMode("simple_select", { featuresId: state.straightArrow.id });
    }    
  },
  // support mobile taps
  onTap: function(state, e) {
    // emulate 'move mouse' to update feature coords
    if (state.controlPoints) this.onMouseMove(state, e);
    // emulate onClick
    this.onClick(state, e);
  },
  // Whenever a user clicks on the map, Draw will call `onClick`（箭头的起始点）
  onClick: function(state, e) {
    // if state.startPoint exist, means its second click
    //change to  simple_select mode（继续画，双击结束）
    var point = this.newFeature({
    type: 'Feature',
    properties: {
      
    },
    geometry: {
      type: 'Point',
      coordinates: [e.lngLat.lng, e.lngLat.lat]
    }
  });
    //this.addFeature(point); //显示点
    //双击结束绘制
   if (
      state.controlPoints &&
      state.controlPoints[state.controlPoints.length-1].x == e.lngLat.lng &&
      state.controlPoints[state.controlPoints.length-1].y == e.lngLat.lat
    ) {
      this.updateUIClasses({ mouse: "pointer" }); 
      this.changeMode("simple_select", { featuresId: state.straightArrow.id });

      this.controlPoints = [];
    } 
    //const controlPoints = [{x:e.lngLat.lng, y:e.lngLat.lat}];
     this.controlPoints.push({x:e.lngLat.lng, y:e.lngLat.lat});//箭头的控制点
     state.controlPoints = this.controlPoints;
  },
  onMouseMove: function(state, e) {
    // if startPoint, update the feature coordinates, using the bounding box concept
    // we are simply using the startingPoint coordinates and the current Mouse Position
    // coordinates to calculate the bounding box on the fly, which will be our rectangle  有起始控制点，通过鼠标停留的改点计算箭头样式显示在地图上，随着移动更新
    if (state.controlPoints) {
       if(state.controlPoints.length  != 0 ){
        const arrowpnts = this.cloneControlPoints(state.controlPoints);
        arrowpnts.push({x:e.lngLat.lng, y:e.lngLat.lat})
        const sevenpnts =  this.calculateParts(arrowpnts);
         
        for(var i=0;i < sevenpnts.length;i++){

           // state.straightArrow.coordinates.push([ sevenpnts[i].x,sevenpnts[i].y]);
            
           state.straightArrow.updateCoordinate("0."+i, sevenpnts[i].x, sevenpnts[i].y ); 
           //state.straightArrow.updateCoordinate("0.2", e.lngLat.lng, e.lngLat.lat); // maxX, maxY
         }
       }
      else{
        //没有控制点的情况
    }
    }
  },
  // keyboard triger while focused on the map：ESC:27
  onKeyUp: function(state, e) {
    if (e.keyCode === 27) return this.changeMode("simple_select");
  },
  onStop: function(state) {
    doubleClickZoom.enable(this);
    this.updateUIClasses({ mouse: "none" });
    this.activateUIButton();

    // check to see if we've deleted this feature
    if (this.getFeature(state.straightArrow.id) === undefined) return;

    //remove last added coordinate 移除最后一个点
   // state.straightArrow.removeCoordinate("0.4"); 
    if (state.straightArrow.isValid()) {
      this.map.fire("draw.create", {
        features: [state.straightArrow.toGeoJSON()]
      });
    } else {
      this.deleteFeature([state.straightArrow.id], { silent: true });
      this.changeMode("simple_select", {}, { silent: true });
    }
    this.controlPoints = [];
  },
  toDisplayFeatures: function(state, geojson, display) {
    const isActivePolygon = geojson.properties.id === state.straightArrow.id;
    geojson.properties.active = isActivePolygon ? "true" : "false";
    if (!isActivePolygon) return display(geojson);
  
    // Only render the rectangular polygon if it has the starting point
    if (!state.controlPoints) return;
    return display(geojson);
  },
  onTrash: function(state) {
    this.deleteFeature([state.straightArrow.id], { silent: true });
    this.changeMode("simple_select");
  },


   /**
         * Method: calculateParts
         * 用于通过控制点计算箭头的所有绘制点
         */
    calculateParts : function(controlPoints){
            //判定少于两个点或者为空，则直接返回
            if(controlPoints == null || controlPoints.length < 2)
            {
                return;
            }
            //判断如果为两个点，且两个点重合时也直接返回.equals
            if(controlPoints.length == 2 && controlPoints[0] == controlPoints[1])
            {
                return;
            }
            //清空原有的所有点
            this.components = [];
            //计算只有两个点时，即直的斜箭头
            if(controlPoints.length == 2)
            {
              return  this.calculateTwoPoints(controlPoints);
            }
            //计算有三个或三个以上的点时，即弯曲的斜箭头
            else
            {
               return this.calculateMorePoints(controlPoints);
            }
        },
         
        /**
         * Method: calculateTwoPoints
         * 计算两个控制点时直箭头的所有绘制点
         * 两个控制点的直箭头绘制点只需要7个就可以构成
         */
    calculateTwoPoints:function (controlPoints){
        this._ratio = 6;
            var controlPois = this.cloneControlPoints(controlPoints);
            //取出第一和第二两个点
            var pointS = controlPois[0];
            var pointE = controlPois[1];
            //计算箭头总长度，即两个控制点的距离
            var l = Math.sqrt((pointE.y-pointS.y)*(pointE.y-pointS.y)+(pointE.x-pointS.x)*(pointE.x-pointS.x));
            //计算直箭头的宽
            var w = l/this._ratio; 

            //计算三角形的底边中心点坐标
            var x_ = pointS.x + (pointE.x - pointS.x)*(this._ratio-1)/this._ratio;
            var y_ = pointS.y + (pointE.y - pointS.y)*(this._ratio-1)/this._ratio;
            //计算与基本向量夹角90度的，长度为w/2的向量数组
            
            var v_lr = this.calculateVector({x:pointE.x-pointS.x,y:pointE.y-pointS.y},Math.PI/2,w/2);
            //获取左右向量
            var v_l = v_lr[0];
            var v_r = v_lr[1];
            //左1点
            var point1 = {x:pointS.x+v_l.x,y:pointS.y+v_l.y};
            //左2点
            var point2 = {x:x_+point1.x-pointS.x,y:y_+point1.y-pointS.y};
            //左3点
            var point3 = {x:2*point2.x-x_,y:2*point2.y-y_};
            //顶点
            var point4 = {x:pointE.x,y:pointE.y};
            //右3点
            var point7 = {x:pointS.x+v_r.x,y:pointS.y+v_r.y};
            //右2点
            var point6 = {x:x_+point7.x-pointS.x,y:y_+point7.y-pointS.y};
            //右1点
            var point5 = {x:2*point6.x-x_,y:2*point6.y-y_};

             return    [point1,point2,point3,point4,point5,point6,point7,point1];//闭合面状
            //state.geometry.coordinates.push([point1,point2,point3,point4,point5,point6,point7,point1]);
            //this.components.push(new SuperMap.Geometry.LinearRing([point1,point2,point3,point4,point5,point6,point7]));
        },

         /**
         * Method: cloneControlPoints
         * 克隆控制点数组
         *
         */
        cloneControlPoints:function(cp){
            var controlPoints = [];
            for(var i = 0; i < cp.length; i++){
                controlPoints.push(cp[i]);//.clone()
            }
            return controlPoints;
        },

         /**
         * Method: calculateVector
         * 计算和基准向量v夹角为a、长度为d的目标向量（理论上有两个，一左一右）
         *
         * Parameters:
         * v - {<Point>} 基准向量
         * a - {Number} 目标向量和基准向量的夹角，默认为90度，这里的单位使用弧度
         * d - {Number} 目标向量的长度，即模，默认为1，即单位向量
         *
         * Returns:
         * {Array(<Point>)} 回目标向量数组（就两个向量，一左一右）:Point
         */
        calculateVector: function(v, a, d){
            if(!a) a =  Math.PI/2;
            if(!d) d = 1;

            //定义目标向量的头部   x 坐标
            var x_1;
            var x_2;
            //定义目标向量的头部   y 坐标
            var y_1;
            var y_2;
            //定义目标向量，一左一右
            var v_l;
            var v_r;

            //计算基准向量v的模
            var d_v = Math.sqrt(v.x*v.x+v.y*v.y);

            //基准向量的斜率为0时，y值不能作为除数，所以需要特别处理
            if(v.y == 0)
            {
                //计算x,会有两个值
                x_1 = x_2 = d_v*d*Math.cos(a)/v.x;
                //根据v.x的正负判断目标向量的左右之分
                if(v.x>0)
                {
                    //计算y
                    y_1 = Math.sqrt(d*d-x_1*x_1);
                    y_2 = -y_1;
                }
                else if (v.x < 0)
                {
                    //计算y
                    y_2 = Math.sqrt(d*d-x_1*x_1);
                    y_1 = -y_2;
 
                }
                v_l = {x:x_1,y:y_1};
                v_r = {x:x_2,y:y_2};
            }
            //此为大多数情况
            else
            {
                //转换为y=nx+m形式
                var n = -v.x/v.y;
                var m = d*d_v*Math.cos(a)/v.y;
                //
                //x*x + y*y = d*d
                //转换为a*x*x + b*x + c = 0
                var a = 1+n*n;
                var b = 2*n*m;
                var c = m*m - d*d;
                //计算x,会有两个值
                x_1 = (-b - Math.sqrt(b*b-4*a*c))/(2*a);
                x_2 = (-b + Math.sqrt(b*b-4*a*c))/(2*a);
                //计算y
                y_1 = n*x_1 + m;
                y_2 = n*x_2 + m;
                //当向量向上时
                if(v.y>=0)
                {
                    v_l = {x:x_1,y:y_1};
                    v_r = {x:x_2,y:y_2};
                }
                //当向量向下时
                else if(v.y < 0)
                {
                    v_l = {x:x_2,y:y_2};
                    v_r = {x:x_1,y:y_1};
                }
            }
            return [v_l,v_r];
        },

         /**
         * Method: calculateMorePoints
         * 计算三个或三个以上的控制点时的所有绘制点
         * 由于中间的控制点之间会进行差值，产生曲线效果，所以所需绘制点会很多
         * 这里使用的思想是将所有用户控制点连接起来形成一条折线段，
         * 然后在拐角进行曲线化处理（二次贝塞尔曲线差值），就形成了效果比较好的箭头
         *
         */
        calculateMorePoints: function(controlPoints){
            var controlPois = this.cloneControlPoints(controlPoints);
            this._ratio = 6;
            //计算箭头总长度
            var l = 0;
            //计算直箭头的宽
            var w = 0;
            for(var i = 0;i < controlPois.length-1;i++)
            {
                //取出首尾两个点
                var pointS = controlPois[i];
                var pointE = controlPois[i+1];
                l += Math.sqrt((pointE.y-pointS.y)*(pointE.y-pointS.y)+(pointE.x-pointS.x)*(pointE.x-pointS.x));
            }
            w = l/this._ratio;
            //定义左右控制点集合
            var points_C_l = [];
            var points_C_r = [];
            //定义尾部左右的起始点
            var point_t_l ={};
            var point_t_r = {};
            //计算中间的所有交点
            for(var j = 0;j < controlPois.length-2;j++)
            {
                var pointU_1 = controlPois[j];//第一个用户传入的点
                var pointU_2 = controlPois[j+1];//第二个用户传入的点
                var pointU_3 = controlPois[j+2];//第三个用户传入的点

                //计算向量
                var v_U_1_2 = {x:pointU_2.x-pointU_1.x,y:pointU_2.y-pointU_1.y};
                var v_U_2_3 = {x:pointU_3.x-pointU_2.x,y:pointU_3.y-pointU_2.y};

                var v_lr_1_2 = this.calculateVector(v_U_1_2,Math.PI/2,w/2);
                var v_l_1_2 = v_lr_1_2[0];
                var v_r_1_2 = v_lr_1_2[1];
                var v_lr_2_3 = this.calculateVector(v_U_2_3,Math.PI/2,w/2);
                var v_l_2_3 = v_lr_2_3[0];
                var v_r_2_3 = v_lr_2_3[1];
                //获取左右
                var point_l_1 = {x:pointU_1.x+v_l_1_2.x,y:pointU_1.y+v_l_1_2.y};
                var point_r_1 = {x:pointU_1.x+v_r_1_2.x,y:pointU_1.y+v_r_1_2.y};
                var point_l_2 = {x:pointU_2.x+v_l_2_3.x,y:pointU_2.y+v_l_2_3.y};
                var point_r_2 = {x:pointU_2.x+v_r_2_3.x,y:pointU_2.y+v_r_2_3.y};
                //向量v_U_1_2和向量v-point_l_1和point_r_1是平行的
                //如果向量a=(x1，y1)，b=(x2，y2)，则a//b等价于x1y2－x2y1=0
                //得到(x-point_l_1.x)*v_U_1_2.y=v_U_1_2.x*(y-point_l_1.y)
                //得到(point_l_2.x-x)*v_U_2_3.y=v_U_2_3.x*(point_l_2.y-y)
                //可以求出坐边的交点(x,y)，即控制点
                var point_C_l = this.calculateIntersection(v_U_1_2,v_U_2_3,point_l_1,point_l_2);
                var point_C_r = this.calculateIntersection(v_U_1_2,v_U_2_3,point_r_1,point_r_2);
                //定义中间的控制点
                var point_C_l_c;
                var point_C_r_c;
                if(j == 0)
                {
                    //记录下箭头尾部的左右两个端点
                    point_t_l = point_l_1;
                    point_t_r = point_r_1;
                    //计算第一个曲线控制点
                    point_C_l_c = {x:(point_t_l.x+point_C_l.x)/2,y:(point_t_l.y+point_C_l.y)/2};
                    point_C_r_c = {x:(point_t_r.x+point_C_r.x)/2,y:(point_t_r.y+point_C_r.y)/2};
                    //添加两个拐角控制点中间的中间控制点
                    points_C_l.push(point_C_l_c);
                    points_C_r.push(point_C_r_c);
                }
                else
                {
                    //获取前一个拐角控制点
                    var point_C_l_q = points_C_l[points_C_l.length-1];
                    var point_C_r_q = points_C_r[points_C_r.length-1];
                    //计算两个拐角之间的中心控制点
                    point_C_l_c = {x:(point_C_l_q.x+point_C_l.x)/2,y:(point_C_l_q.y+point_C_l.y)/2};
                    point_C_r_c = {x:(point_C_r_q.x+point_C_r.x)/2,y:(point_C_r_q.y+point_C_r.y)/2};
                    //添加两个拐角控制点中间的中间控制点
                    points_C_l.push(point_C_l_c);
                    points_C_r.push(point_C_r_c);
                }
                //添加后面的拐角控制点
                points_C_l.push(point_C_l);
                points_C_r.push(point_C_r);
            }
            //计算



            //进入计算头部
            //计算一下头部的长度
            var pointU_E2 = controlPois[controlPois.length-2];//倒数第二个用户点
            var pointU_E1 = controlPois[controlPois.length-1];//最后一个用户点
            //
            var v_U_E2_E1 = {x:pointU_E1.x-pointU_E2.x,y:pointU_E1.y-pointU_E2.y};
            var head_d = Math.sqrt(v_U_E2_E1.x*v_U_E2_E1.x + v_U_E2_E1.y*v_U_E2_E1.y);
            //定义头部的左右两结束点
            var point_h_l;
            var point_h_r;

            //头部左右两向量数组
            var v_lr_h = [];
            var v_l_h = {};
            var v_r_h = {};
            //定义曲线最后一个控制点，也就是头部结束点和最后一个拐角点的中点
            var point_C_l_e = {};
            var point_C_r_e = {};
            //定义三角形的左右两个点
            var point_triangle_l = {};
            var point_triangle_r = {};

            //获取当前的最后的控制点，也就是之前计算的拐角点
            var point_C_l_eq = points_C_l[points_C_l.length-1];
            var point_C_r_eq = points_C_r[points_C_r.length-1];

            //三角的高度都不够
            if(head_d <= w)
            {
                v_lr_h = this.calculateVector(v_U_E2_E1,Math.PI/2,w/2);
                v_l_h = v_lr_h[0];
                v_r_h = v_lr_h[1];
                //获取头部的左右两结束点
                point_h_l = {x:pointU_E2.x+v_l_h.x,y:pointU_E2.y+v_l_h.y};
                point_h_r = {x:pointU_E2.x+v_r_h.x,y:pointU_E2.y+v_r_h.y};


                //计算最后的控制点
                point_C_l_e = {x:(point_C_l_eq.x+point_h_l.x)/2,y:(point_C_l_eq.y+point_h_l.y)/2};
                point_C_r_e = {x:(point_C_r_eq.x+point_h_r.x)/2,y:(point_C_r_eq.y+point_h_r.y)/2};

                //添加最后的控制点（中心点）
                points_C_l.push(point_C_l_e);
                points_C_r.push(point_C_r_e);


                //计算三角形的左右两点
                point_triangle_l = {x:2*point_h_l.x-pointU_E2.x,y:2*point_h_l.y-pointU_E2.y};
                point_triangle_r = {x:2*point_h_r.x-pointU_E2.x,y:2*point_h_r.y-pointU_E2.y};
            }
            //足够三角的高度
            else
            {
                //由于够了三角的高度，所以首先去掉三角的高度

                //计算向量
                var v_E2_E1 = {x:pointU_E1.x-pointU_E2.x,y:pointU_E1.y-pointU_E2.y};
                //取模
                var v_E2_E1_d = Math.sqrt(v_E2_E1.x*v_E2_E1.x+v_E2_E1.y*v_E2_E1.y);
                //首先需要计算三角形的底部中心点
                var point_c = {x:pointU_E1.x-v_E2_E1.x*w/v_E2_E1_d,y:pointU_E1.y-v_E2_E1.y*w/v_E2_E1_d};
                //计算出在三角形上底边上头部结束点

                v_lr_h = this.calculateVector(v_U_E2_E1,Math.PI/2,w/2);
                v_l_h = v_lr_h[0];
                v_r_h = v_lr_h[1];
                //获取头部的左右两结束点
                point_h_l = {x:point_c.x+v_l_h.x,y:point_c.y+v_l_h.y};
                point_h_r = {x:point_c.x+v_r_h.x,y:point_c.y+v_r_h.y};

                //计算最后的控制点
                point_C_l_e = {x:(point_C_l_eq.x+point_h_l.x)/2,y:(point_C_l_eq.y+point_h_l.y)/2};
                point_C_r_e = {x:(point_C_r_eq.x+point_h_r.x)/2,y:(point_C_r_eq.y+point_h_r.y)/2};

                //添加最后的控制点（中心点）
                points_C_l.push(point_C_l_e);
                points_C_r.push(point_C_r_e);

                //计算三角形的左右点
                point_triangle_l = {x:2*point_h_l.x-point_c.x,y:2*point_h_l.y-point_c.y};
                point_triangle_r = {x:2*point_h_r.x-point_c.x,y:2*point_h_r.y-point_c.y};
            }

            //使用控制点计算差值_______________________________________________________________________________
            //计算贝塞尔的控制点
            //var points_BC_l = SuperMap.Geometry.LineString.createBezier2(points_C_l).components;
            var points_BC_l = PlotBaseClass.calculatePointsFBZ2(points_C_l);
            //var points_BC_r = SuperMap.Geometry.LineString.createBezier2(points_C_r).components;
             var points_BC_r = PlotBaseClass.calculatePointsFBZ2(points_C_r);
            //组合左右点集和三角形三个点
            var pointsR = [point_t_l];
            //首先连接左边的差值曲线
            pointsR = pointsR.concat(points_BC_l);
            //添加左边头部结束点
            pointsR.push(point_h_l);
            //添加三角形左边点
            pointsR.push(point_triangle_l);
            //添加三角形顶点
            pointsR.push(pointU_E1);
            //添加三角形右边点
            pointsR.push(point_triangle_r);
            //添加右边头部结束点
            pointsR.push(point_h_r);
            //合并右边的所有点（先把右边的点倒序）
            pointsR = pointsR.concat(points_BC_r.reverse());

            //添加右边尾部起始点
            pointsR.push(point_t_r);
            return pointsR
           // this.components.push(new SuperMap.Geometry.LinearRing(pointsR));

        },
           /**
         * Method: calculateIntersection
         * 计算两条直线的交点
         * 通过向量的思想进行计算，需要提供两个向量以及两条直线上各自一个点
         *
         * Parameters:
         * v_1 - {<Point>} 直线1的向量
         * v_2 - {<Point>} 直线2的向量
         * points1 - {<Point>} 直线1上的任意一点
         * points2 - {<Point>} 直线2上的任意一点
         *
         * Returns:
         * {Array(<SuperMap.Geometry.Point>)} 返回交点
         */
        calculateIntersection: function(v_1, v_2, point1, point2){
            //定义交点的坐标
            var x;
            var y;
            //如果向量v_1和v_2平行
            if(v_1.y*v_2.x-v_1.x*v_2.y == 0)
            {
                //平行也有两种情况
                //同向
                if(v_1.x*v_2.x>0 || v_1.y*v_2.y>0)
                {
                    //同向直接取两个点的中点
                    x = (point1.x+point2.x)/2;
                    y = (point1.y+point2.y)/2;
                }
                //反向
                else
                {
                    //如果反向直接返回后面的点位置
                    x = point2.x;
                    y = point2.y;
                }
            }
            else
            {
                //
                x = (v_1.x*v_2.x*(point2.y-point1.y)+point1.x*v_1.y*v_2.x-point2.x*v_2.y*v_1.x)/(v_1.y*v_2.x-v_1.x*v_2.y);
                if(v_1.x!=0)
                {
                    y = (x-point1.x)*v_1.y/v_1.x+point1.y;
                }
                //不可能v_1.x和v_2.x同时为0
                else
                {
                    y = (x-point2.x)*v_2.y/v_2.x+point2.y;
                }
            }
            return {x:x,y:y};

        }
};

      

       
export default DrawStraightArrow;